from calculator.calculator import Calculator

class MonkBaseCalculator(Calculator):
    
    MASTERY_CNAHCE_CONVERSION_COEFFICIENT_MONK_WINDWALKER = 1.4
    
    CRITICAL_DAMAGE_RATE_BASE = 2.0
    
    SPELL_WEAPON_COEFFIECIENT_2H = 1.0
    SPELL_WEAPON_COEFFIECIENT_DW = 0.898882
    # Stance of Fierce Tiger - Increases damage done by 20%
    STANCE_COEFFICENT = 1.2
    # Way of Monk (Passive): 
    # Dual-wield one-handed weapons
    # Auto attack damage increased by 40%.
    WAY_OF_MONK_DW_DAMAGE_COEFFICIENT = .4
    # Two-handed weapons
    # Melee attack speed increased by 40%.
    WAY_OF_MONK_2H_IAS_COEFFICIENT = .4
    # Tiger Strike
    TIGER_STRIKE_TRIGGER_RATE = .08
    TIGER_STRIKE_CHARGE_NUMBER = 4.0
    TIGER_STRIKE_IAS_COEFFICIENT = .5
    # energy base
    BASE_ENERGY_REGEN_PER_SECOND = 10.0
    ENERGY_POOL_SIZE = 100.0
    ENERGY_REFUND_PERCENTAGE_MISS = .8
    # Jab
    JAB_ENERGY_COST = 40.0
    JAB_CHI_GAIN = 2.0
    # Spinning Fire Blossom
    SPINNING_FIRE_BLOSSOM_BASE_DAMAGE = 766.0
    SPINNING_FIRE_BLOSSOM_BONUS_RANGE = 10 # yard
    SPINNING_FIRE_BLOSSOM_RANGED_DAMAGE_MODIFIER = 1.5
    # level 45 talents
    CHI_BREW_CD = 90.0
    CHI_BREW_CHI_GAIN = 4.0
    POWER_STRIKE_CD = 20.0 # 5.1
    POWER_STRIKE_ADDITIONAL_CHI_GAIN = 1.0
    ASCENSION_ENERGY_REGEN_RATE = 1.15 # 5.1
    # long cd spell
    ENERGIZING_BREW_CD = 60.0
    ENERGIZING_BREW_BASE_LAST_TIME = 6.0
    ENERGIZING_BREW_ENERGY_GAIN_PER_SECOND = 10.0
    # chi cost spell cd
    RISING_SUN_KICK_CD = 8.0
    RISING_SUN_KICK_DAMAGE_BONUS_MULTIPLIER = 1.1 # 5.05
    # 5.1
    # RISING_SUN_KICK_DAMAGE_BONUS_MULTIPLIER = 1.15
    FISTS_OF_FURY_CD = 25.0
    # Tiger Palm ignore armor buff
    TIGER_PALM_BUFF_LENGTH = 20.0
    TIGER_PALM_MAX_STACK = 1.0
    TIGER_PALM_ARMOR_IGNORE_PER_STACK = .3
    # spell chi cost
    TIGER_PALM_CHI_COST = 1.0
    BLACKOUT_KICK_CHI_COST = 2.0
    RISING_SUN_KICK_CHI_COST = 2.0
    FISTS_OF_FURY_CHI_COST = 3.0
    # channel time affected by haste
    # TODO
    FISTS_OF_FURY_CHANNEL_TIME = 4.0
    FISTS_OF_FURY_TICK_NUMBER = 5.0
    
    # Tiger Eye Brew
    TIGER_EYE_CHI_COST_PER_STACK = 4
    TIGER_EYE_DAMAGE_BONUS_PER_STACK = .02
    TIGER_EYE_LAST_TIME = 15.0
    
    # Invoke, White Tiger
    WHITE_TIGER_CD = 180.0
    WHITE_TIGER_LAST_TIME = 45.0
    WHITE_TIGER_HESITATION_TIME = 5.0
    WHITE_TIGER_AP_SCALING = .5
    WHITE_TIGER_BASE_ATTACK_SPEED = 1.0
    WHITE_TIGER_AUTO_ATTACK_BASE_DAMAGE = 1159.0
    WHITE_TIGER_LIGHTNING_TICK_BASE_DAMAGE = 321.0
    WHITE_TIGER_LIGHTNING_AP_COEFFICIENT = .505
    WHITE_TIGER_LIGHTNING_CD = 6.0
    WHITE_TIGER_LIGHTNING_TICK = 5.0
    
    # Bloodlust / Heroism
    BLOODLUST_LAST_TIME = 40.0
    BLOODLUST_HASTE_INCREASE = .3
    BLOODLUST_CD = 600.0
    
    # Set Bonus
    MONK_2T14_WINDWALKER_FOF_CD_REDUCTION = 5.0
    MONK_4T14_WINDWALKER_EB_DURATION_INCREASE = 5.0
    
    
    MONK_SPELLS = {'AUTO_ATTACK_MH':{'TYPE':'MELEE', 'HAND':'MH', 'COEFFICIENT':0},
                   'AUTO_ATTACK_OH':{'TYPE':'MELEE', 'HAND':'OH', 'COEFFICIENT':0},
                   'TIGER_STRIKE_MH':{'TYPE':'MELEE', 'HAND':'MH', 'COEFFICIENT':0},
                   'TIGER_STRIKE_OH':{'TYPE':'MELEE', 'HAND':'OH', 'COEFFICIENT':0},
                   'JAB':{'TYPE':'MELEE', 'HAND':'MH', 'COEFFICIENT':1.5}, 
                   'TIGER_PALM':{'TYPE':'MELEE', 'HAND':'MH', 'COEFFICIENT':3.0},
                   'BLACKOUT_KICK':{'TYPE':'MELEE', 'HAND':'MH', 'COEFFICIENT':8*0.89}, 
                   'BLACKOUT_KICK_DOT':{'TYPE':'MELEE', 'HAND':'NONE', 'COEFFICIENT':0.2}, 
                   'RISING_SUN_KICK':{'TYPE':'MELEE', 'HAND':'MH', 'COEFFICIENT':14.4*0.89}, 
                   'FISTS_OF_FURY':{'TYPE':'MELEE', 'HAND':'MH', 'COEFFICIENT':7.5*0.89}, 
                   'EXPEL_HALM':{'TYPE':'SPELL', 'HAND':'MH', 'COEFFICIENT':7*0.5}, 
                   'SPINNING_FIRE_BLOSSOM':{'TYPE':'SPELL', 'HAND':'MH', 'COEFFICIENT':.665}
                   }
    
    EP_STATS = ['agi', 'mastery', 'hit', 'exp', 'haste', 'crit']
    
    
    # @ Override for monk 
    def target_armor(self, throw):
        target_armor = self.RAID_BOSS_ARMOR_VALUE
        if self.buffs.weaken_armor:
            target_armor *= (1 - self.WEAKENED_ARMOR_DEBUFF_PENCENTAGE)
        target_armor *= (1 - self.TIGER_PALM_ARMOR_IGNORE_PER_STACK * self.TIGER_PALM_MAX_STACK)
        # Sharterring Throw
        if throw:
            target_armor *= (1 - self.SHARTTERING_ARMOR_REDUCTION)
        return target_armor
    
    
    def get_mastery_chance_windwalker(self):
        mastery = self.stats.get_mastery_from_rating()
        mastery += self.buffs.get_mastery_buff_modifier()
        
        return mastery * self.MASTERY_CNAHCE_CONVERSION_COEFFICIENT_MONK_WINDWALKER
    
    
    def crit_chance_melee(self):
        return self.base_crit_chance() + self.stats.get_crit_from_agi()
    
    
    def crit_chance_spell(self):
        return self.base_crit_chance() + self.stats.get_crit_from_int()
    
    
    # Basically deal with Bloodlust / Heroism
    def haste_multiplier_total(self):
        haste = 1 + self.stats.get_haste_from_rating()
        bloodlust_uptime = self.buffs.bloodlust * self.get_spell_uptime(self.BLOODLUST_LAST_TIME, self.BLOODLUST_CD)
        haste *= (1 + self.BLOODLUST_HASTE_INCREASE * bloodlust_uptime)
        
        return haste
    
    
    def get_spell_haste_multiplier(self):
        haste = self.haste_multiplier_total()
        haste *= self.buffs.get_spell_haste_buff_multiplier()
        
        return haste
    
    
    def get_ias_multiplier(self):
        ias = self.haste_multiplier_total()
        ias *= self.buffs.get_ias_buff_multiplier()
        # two-hand passive
        if self.is_two_hand_weapon():
            ias *= (self.WAY_OF_MONK_2H_IAS_COEFFICIENT + 1)
        # update ias with Tiger Strike
        ias *= (1 + self.TIGER_STRIKE_IAS_COEFFICIENT * self.tiger_strike_uptime())
        
        return ias
    
    
    def get_ias_multiplier_with_tiger_strike(self):
        ias = self.haste_multiplier_total()
        ias *= self.buffs.get_ias_buff_multiplier()
        # two-hand passive
        if self.is_two_hand_weapon():
            ias *= (self.WAY_OF_MONK_2H_IAS_COEFFICIENT + 1)
        ias *= (1 + self.TIGER_STRIKE_IAS_COEFFICIENT)
        
        return ias
    
    
    def get_ias_multiplier_without_tiger_strike(self):
        ias = self.haste_multiplier_total()
        ias *= self.buffs.get_ias_buff_multiplier()
        # two-hand passive
        if self.is_two_hand_weapon():
            ias *= (self.WAY_OF_MONK_2H_IAS_COEFFICIENT + 1)
        
        return ias
    
    
    
    def auto_attack_hit_damage(self, hand):
        if hand == 'MH':
            weapon_speed = self.stats.mh.speed
            weapon_dps = self.stats.mh.dps
        elif hand == 'OH':
            if self.is_two_hand_weapon():
                return 0
            else:
                weapon_speed = self.stats.oh.speed
                weapon_dps = self.stats.oh.dps
        
        damage = (weapon_dps + self.stats.ap / 14) * weapon_speed
        # OH penaty
        if hand == 'OH':
            damage *= self.OH_DAMAGE_PENATY_RATE
        # DW passive     
        if self.is_dual_wield():
            damage *= (1 + self.WAY_OF_MONK_DW_DAMAGE_COEFFICIENT)
            
        damage *= self.damage_modifier_by_armor()
        damage *= self.buffs.get_physical_vulnerability_multiplier()
            
        return damage
    
    
    def tiger_strike_uptime(self):
        # uptime = c / 1 + ias
        uptime = self.tiger_strike_coverage_on_auto_attack() / (1 + self.TIGER_STRIKE_IAS_COEFFICIENT)
        return uptime
        
        
    def tiger_strike_coverage_on_auto_attack(self):
        # c = 1 - (1 - p) ^ 4
        coverage = 1 - pow((1 - self.TIGER_STRIKE_TRIGGER_RATE), self.TIGER_STRIKE_CHARGE_NUMBER)
        return coverage
    
        
    def tiger_strike_count(self, hand):
        return self.tiger_strike_coverage_on_auto_attack() * self.auto_attack_count(hand)
    
    
    # auto-attack two-roll
    def auto_attack_land_chance(self, hand):
        if self.is_two_hand_weapon():
            if hand == 'MH':
                land_chance = self.hit_chance_melee_special(hand, dodgeable=True, parryable=False)
            else:
                land_chance = 0
        else:
            land_chance = self.land_chance_melee_dw(hand, dodgeable=True, parryable=False)
        
        return land_chance
    
    
    def spell_hit_chance(self, spell):     

        hand = self.MONK_SPELLS.get(spell).get('HAND')
        spell_type = self.MONK_SPELLS.get(spell).get('TYPE')
            
        if spell_type == 'MELEE':
            hit_chance = self.hit_chance_melee_special(hand, dodgeable=True, parryable=False)
        elif spell_type == 'SPELL':
            hit_chance = self.hit_chance_spell()     
        return hit_chance
    
    
    def spell_weapon_damage_multiplier(self):
        multiplier = 1
        #get ap
        ap = self.stats.ap
        if self.is_two_hand_weapon():
            # get weapon dps
            weapon_dps = self.stats.mh.dps
            multiplier = self.SPELL_WEAPON_COEFFIECIENT_2H * weapon_dps + ap / 14
 
        else:
            # get weapon dps
            weapon_dps_mh = self.stats.mh.dps
            weapon_dps_oh = self.stats.oh.dps
            multiplier = self.SPELL_WEAPON_COEFFIECIENT_DW * (weapon_dps_mh + weapon_dps_oh / 2) + ap / 14
            
        return multiplier
    
    
    def spell_hit_damage(self, spell):
        if not self.MONK_SPELLS.has_key(spell):
            print 'no such spell'
        elif spell == 'SPINNING_FIRE_BLOSSOM':
            spell_damage = self.SPINNING_FIRE_BLOSSOM_BASE_DAMAGE + self.stats.ap * self.MONK_SPELLS.get(spell).get('COEFFICIENT')
        else:
            spell_coefficient = self.MONK_SPELLS.get(spell).get('COEFFICIENT')
            spell_damage = self.spell_weapon_damage_multiplier() * spell_coefficient
            
        if self.MONK_SPELLS.get(spell).get('TYPE') == 'MELEE':
            spell_damage *= self.damage_modifier_by_armor()
            spell_damage *= self.buffs.get_physical_vulnerability_multiplier()
        elif self.MONK_SPELLS.get(spell).get('TYPE') == 'SPELL':
            spell_damage *= self.buffs.get_spell_vulnerability_multiplier()

        return spell_damage
    
    
    def get_spell_crit_chance(self):
        self.crit_chance = {}
        for spell in self.MONK_SPELLS:
            spell_type = self.MONK_SPELLS.get(spell).get('TYPE')
            if spell_type == 'MELEE':
                # add agi crit bonus
                self.crit_chance[spell] = self.crit_chance_melee()
            elif spell_type == 'SPELL':
                self.crit_chance[spell] = self.crit_chance_spell()
        
        self.crit_chance['BLACKOUT_KICK_DOT'] = 0
        
        if self.is_two_hand_weapon():
            self.crit_chance['AUTO_ATTACK_OH'] = 0
            self.crit_chance['TIGER_STRIKE_OH'] = 0
    
    
    def update_white_tiger_stats(self):
        self.pet.ap = self.stats.ap * self.WHITE_TIGER_AP_SCALING
        mh = self.stats.mh.weapon_type
        oh = self.stats.oh.weapon_type
        exp = max(self.stats.get_exp_rate_total(mh), self.stats.get_exp_rate_total(oh))
        self.pet.hit = (self.stats.get_hit_from_rating() + exp) / 2
        self.pet.exp = (self.stats.get_hit_from_rating() + exp) / 2
        self.pet.crit = self.crit_chance_melee()
        self.pet.ias = self.get_ias_multiplier()
        self.pet.attack_speed = self.WHITE_TIGER_BASE_ATTACK_SPEED
        
        
    def white_tiger_auto_attack_hit_damage(self):
        damage = self.WHITE_TIGER_AUTO_ATTACK_BASE_DAMAGE + self.pet.ap / 14
        damage *= self.buffs.get_physical_vulnerability_multiplier()
        return damage
    
    
    def white_tiger_auto_attack_land_chance(self, dodgeable=True, parryable=False):
        hit_rate = self.pet.hit
        miss_chance = max(self.BASE_MELEE_MISS_CHANCE - hit_rate, 0)
           
        expertise_rate = self.pet.exp
        
        dodge_chance = 0
        parry_chance = 0
        
        if dodgeable:
            dodge_chance = max(self.BASE_DODGE_CHANCE - expertise_rate, 0)
        
        if parryable:
            parry_chance = max(self.BASE_PARRY_CHANCE - (expertise_rate - self.BASE_DODGE_CHANCE), 0)
        
        land_chance = 1 - miss_chance - dodge_chance - parry_chance
        return land_chance
        
    
    def white_tiger_lightning_tick_damage(self):
        damage = self.WHITE_TIGER_LIGHTNING_TICK_BASE_DAMAGE + self.pet.ap * self.WHITE_TIGER_LIGHTNING_AP_COEFFICIENT
        damage *= self.buffs.get_spell_vulnerability_multiplier()
        return damage
    
    # 5.1
    def fists_of_fury_channel_time(self):
        return self.FISTS_OF_FURY_CHANNEL_TIME / self.get_spell_haste_multiplier()
    
    
    def white_tiger_lightning_hit_chance(self):  
        miss_chance = max(self.BASE_SPELL_MISS_CHANCE - self.pet.hit - self.pet.exp, 0)
        return 1 - miss_chance
    